import type { Base } from './types/base'
import type { Worker } from './types/worker'
import type { Remote } from './types/remote'
import { ApplianceRemote } from './remote'
import { ApplianceWorker } from './worker'
import { isPromise } from '@vue/shared'
import type { BaseController } from '../BaseAppliance/definition'

export const createDatasource: () => Base.DataSource = () => ({
  /**
   * 控制页入参
   */
  haId: '',
  vib: '',
  type: '',
  brand: '',
  /**
   * 页面状态
   */
  loaded: false,
  loadSuccess: false,
  /**
   * 家电数据
   */
  detail: null,
  settings: [],
  status: [],
  commands: [],
  events: [],
})

/**
 * 家电详情页 Store 绑定的 Worker
 */
const workerRecords = new WeakMap<Base.FullStore, Worker.ApplianceWorker<Base.FullStore>>()
export function useWorker<Store extends Base.FullStore>(store: Store): Worker.ApplianceWorker<Store> {
  let worker = workerRecords.get(store)
  if (!worker) {
    worker = new ApplianceWorker(store) as Worker.ApplianceWorker<Base.FullStore>
    workerRecords.set(store, worker)
  }
  return worker as Worker.ApplianceWorker<Store>
}

/**
 * 家电详情页 Store 绑定的 Remote
 */
const remoteRecords = new WeakMap<Base.FullStore, Remote.ApplianceRemote<Base.FullStore>>()
export function useRemote<State extends Base.FullStore>(store: State): Remote.ApplianceRemote<State> {
  let remote = remoteRecords.get(store)
  if (!remote) {
    remote = new ApplianceRemote<State>(store)
    remoteRecords.set(store, remote)
  }
  return remote as Remote.ApplianceRemote<State>
}

/**
 * Demo 模式方法
 */
export function getNoopActions<TAction>(actions: TAction): TAction {
  return Object.keys(actions as Record<string, Function>).reduce<Record<string, Function>>(
    (noopActions, actionName) => {
      noopActions[actionName] = () => {}
      return noopActions
    },
    {}
  ) as TAction
}
export function injectState<TState>(stateCreator: () => TState, injector: (state: TState) => TState | void) {
  const state = stateCreator()
  const injection = injector(state)
  return injection || state
}

/**
 * Actions添加错误捕获方法
 */
export function wrapSafeActions<TStore extends BaseController.Store, TAction extends BaseController.Actions>(
  actions: TAction
): TAction {
  return Object.entries(actions).reduce((safeActions, [prop, rawAction]) => {
    // let isThrowable = false

    const errorHandler = (e: any) => console.error('Store Error: ', e)

    const safeAction = function () {
      try {
        const ret = rawAction.apply(this, arguments)
        if (isPromise(ret)) {
          return ret.catch((e) => {
            errorHandler(e)
            // return isThrowable ? Promise.reject(e) : Promise.resolve()
          })
        }
        return ret
      } catch (e) {
        errorHandler(e)
        // if (isThrowable) {
        //   throw e
        // }
      }
    } as (this: TStore) => void
    // safeAction.setThrowable = (throwable: boolean) => {
    //   isThrowable = throwable
    // }

    safeActions[prop] = safeAction
    return safeActions
  }, {} as any)
}
